
var gl;
function initGL(g_canvas) {
    "use strict";
    try {
        gl = g_canvas.getContext("experimental-webgl");
        gl.viewportWidth = g_canvas.width;
        gl.viewportHeight = g_canvas.height;
    } catch (e) {
    }
    if (!gl)
    {
        alert("Could not initialise WebGL, sorry :-(");
    }
    }
    
    function checkGLError() {
        "use strict";
        var error = gl.getError();
        if (error != gl.NO_ERROR) {
            var str = "GL Error: " + error;
            document.body.appendChild(document.createTextNode(str));
        }
    }


var requestAnimFrame = (function() {
    "use strict";
    return window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.oRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        function(/* function FrameRequestCallback */ callback, /* DOMElement Element */ element) {
       //window.setTimeout(callback, 1000/60);
        };
})();


    var g_player;

    
    var main_cam,
        back_cam,
        front_cam;

    var cam_list = [];


    var sun_vec = [0.707, 0.707, 0.0];

    var prev_time = 0,
        cur_time = 0,
        delta_time = 0;
    
    var tilt_cam_time = 0;
    

    var currentlyPressedKeys = {};
    var b_acc_forward = false;
    var b_acc_backward = false;

    function handleKeyDown(event) {
        "use strict";
        currentlyPressedKeys[event.keyCode] = true;

        //if (String.fromCharCode(event.keyCode) == 18) {
        if ( (event.keyCode == 32) || (event.keyCode == 39) || (event.keyCode == 68) || (event.keyCode == 38) || (event.keyCode == 87) ) {
            //alert("Space pressed");
            b_acc_forward = true;
        }
        if ( ( event.keyCode == 37) || (event.keyCode == 65)|| (event.keyCode == 40) || (event.keyCode == 83) ) {
            b_acc_backward = true;
        }
        if (String.fromCharCode(event.keyCode) == "F") {
            
            var cam_index = 0;
            
            for(var i = 0; i < cam_list.length; i++)
            {
                if(cam_list[i] == g_render_state.current_cam)
                {
                    cam_index = i;
                }
            }
            
            if(cam_index < cam_list.length - 1)
            {
                cam_index++;
            } else
            {
                cam_index = 0;
            }
            
            g_render_state.current_cam = cam_list[cam_index];
        }
        if (event.keyCode == 16) {  //Shift
            g_player.IncrementGear();
        }
    }

  function handleKeyUp(event) {
    "use strict";
    currentlyPressedKeys[event.keyCode] = false;
    
    if ( (event.keyCode == 32) || (event.keyCode == 39) || (event.keyCode == 68) || (event.keyCode == 38) || (event.keyCode == 87) )
    {
        b_acc_forward = false;
    }
    
    if ( ( event.keyCode == 37) || (event.keyCode == 65)|| (event.keyCode == 40) || (event.keyCode == 83))
    {
            b_acc_backward = false;
    }
  }

    var global_device_aspect;
    
    var g_canvas;
    
    var g_renderer;
    
    function DrawFunc(){
        g_player.Draw();
        //node.Draw();
        tree.Draw();

        //g_start_hint.Draw();
    }
    
    var win_texture;
    var font_texture;

    var tree;

    function webGLStart() {
        "use strict";
        //console.time("Loading");
        
        g_canvas = document.getElementById("canvas1");
        
        g_canvas.width  = window.innerWidth - 16;
        g_canvas.height = g_canvas.width * (9/16);
        
        
        global_device_aspect = 9/16;
        
        g_canvas.addEventListener("mousedown", GetClick, false);
        g_canvas.addEventListener("mousemove", GetMove, false);
        g_canvas.addEventListener("mouseup", GetUp, false);
        
        
        initGL(g_canvas);
        

        gl.clearColor(0.0, 0.0, 0.0, 1.0);
        gl.enable(gl.DEPTH_TEST);


        g_renderer = new Renderer("default_config.txt");
        
        //console.time("InitShaders");
        g_renderer.InitShaders();
        //console.timeEnd("InitShaders");
        
        //console.time("LoadTextures");
        g_renderer.LoadTexture("checker.png", true);
        win_texture = g_renderer.LoadTexture("window.png", false, true);
        font_texture = g_renderer.LoadTexture("ExportedFont1024_2.png", true);
        //console.timeEnd("LoadTextures");
        
        g_renderer.set_draw_func(DrawFunc);

        prev_time = Date.now();
        
        g_prev_time = Date.now();
        g_cur_time = Date.now();

        g_player = new Car("lamb/lamb_default.txt");
        

        //main_cam = new Camera([-100.0, 20.0, 30.0], [0.0, 90.0*PI_DIV_180, 0.0]);
        main_cam = new Camera([-100.0*8*1, 20.0*8*1, 30.0*8*1], [0.0, 90.0*PI_DIV_180, 0.0]);
        main_cam.Perspective(45, gl.viewportWidth / gl.viewportHeight, 0.5, 10000.0);
        
        back_cam = new Camera([0.0, 20.0*8, -70.0*8], [0.0, 180.0*PI_DIV_180+0.001, 0.0]);
        back_cam.Perspective(45, gl.viewportWidth / gl.viewportHeight, 0.5, 100000.0);
        
                
        front_cam = new Camera([0.0, 20.0*8, 70.0*8], [0.0, 0.0*PI_DIV_180, 0.0]);
        front_cam.Perspective(45, gl.viewportWidth / gl.viewportHeight, 0.5, 100000.0);
        

        cam_list.push(main_cam);
        cam_list.push(back_cam);
        cam_list.push(front_cam);
        
        
        g_render_state.current_cam = cam_list[0];//main_cam;

        
        document.onkeydown = handleKeyDown;
        document.onkeyup = handleKeyUp;

        
        
        //node = new BVHNode(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
        //var mesh = new Mesh("land.mesh");
        //node.set_mesh(mesh);
        //node.set_diff_tex(0);

        tree = new BVHTree("maps/map1.txt");
        
        InitGameUI();
        
        gl.enable(gl.CULL_FACE);
        gl.cullFace(gl.BACK);
        //setTimeout(drawScene, 100);
        
        //console.timeEnd("Loading");
        
        setTimeout(step, 100);
        //current_program = carpaint_program;
        
        
    }
    
    var node;
    
    var UPDATE_DELTA = 1000/60;
    
    var g_cur_time = 0,
        g_delta_time = 0,
        g_prev_time = 0,
        g_time_acc = 0;
    
    function step(){
        "use strict";
        //console.time("update");
        
        g_cur_time = Date.now();
        g_delta_time = g_cur_time - g_prev_time;
        if(g_delta_time > 200)
        {
            g_delta_time = 200;
        }
        g_prev_time = g_cur_time;
        
        g_time_acc += g_delta_time;
        
        while(g_time_acc >= UPDATE_DELTA)
        {
            Update(UPDATE_DELTA);
            g_time_acc -= UPDATE_DELTA;
        }
        
        //console.log((g_player.velocity()[2] / (100*1000))*(1000*60*60));

        //console.timeEnd("update");
        //console.time("render");
        
        g_renderer.DrawScene();
        
        //console.timeEnd("render");
        
        window.requestAnimFrame(step);
        
    }
    
    function resize_canvas(){
        "use strict";

        g_canvas.width = window.innerWidth - 16;

        g_canvas.height = g_canvas.width * (9/16);
                
        try {
            gl.viewportWidth = g_canvas.width;
            gl.viewportHeight = g_canvas.height;
            
            g_renderer.Resize();
        } catch (e) {
        }
    }
    
    /***************************************************************************/
    
    function Update(delta) {
        "use strict";
        if(b_acc_forward)
        {
            g_player.Accelerate(true);
        } else
        {
            if(b_acc_backward)
            {
                g_player.Accelerate(false);
            } else
            {
                g_player.set_acceleration([0.0, 0.0, 0.0]);
            }
        }
        
        g_player.Update(delta);
            
                
        if( g_player.position()[2] < 100000)
        {
            g_render_state.current_cam.Follow(g_player);
        }
    
    }
    
    
    /***************************************************************************/
    
    var g_toasts = [];
    
    function ShowToast(text, x, y, scale, delay, duration){
        "use strict";
        var new_toast = new TypeMesh(text, x, y, scale);
        //new_toast.Draw();
        g_toasts.push(new_toast);
        //g_toasts[g_toasts.length-1].duration = duration;
        g_toasts[g_toasts.length-1].start_time = cur_time + delay;
        g_toasts[g_toasts.length-1].stop_time = cur_time + delay + duration;
    }
    
    /***************************************************************************/
    
    var g_materials = {
        "carpaint" : {
            Use : function(){
                "use strict";
                if(g_render_state.current_program.hasOwnProperty("Kd"))
                {
                    gl.uniform1f(g_render_state.current_program.Kd, PackRGBA([1.0, 0.9, 0.0, 1.0]));
                }
                if(g_render_state.current_program.hasOwnProperty("Ka"))
                {
                    gl.uniform1f(g_render_state.current_program.Ka, PackRGBA([0.2, 0.25, 0.3, 0.0]));
                }
                if(g_render_state.current_program.hasOwnProperty("Kr"))
                {
                    gl.uniform1f(g_render_state.current_program.Kr, PackRGBA([0.8, 0.8, 0.6, 0.0]));
                }
            }
        },
        "carglass" : {
            Use : function(){
                "use strict";
                if(g_render_state.current_program.hasOwnProperty("Kd"))
                {
                    gl.uniform1f(g_render_state.current_program.Kd, PackRGBA([0.0, 0.0, 0.0, 1.0]));
                }
                if(g_render_state.current_program.hasOwnProperty("Ka"))
                {
                    gl.uniform1f(g_render_state.current_program.Ka, PackRGBA([0.0, 0.0, 0.0, 0.0]));
                }
                if(g_render_state.current_program.hasOwnProperty("Kr"))
                {
                    gl.uniform1f(g_render_state.current_program.Kr, PackRGBA([0.8, 0.8, 0.8, 1.0]));
                }
            }
        },
        "tire" : {
            Use : function(){
                "use strict";
                if(g_render_state.current_program.hasOwnProperty("Kd"))
                {
                    gl.uniform1f(g_render_state.current_program.Kd, PackRGBA([1.0, 1.0, 1.0, 1.0]));
                }
                if(g_render_state.current_program.hasOwnProperty("Ka"))
                {
                    gl.uniform1f(g_render_state.current_program.Ka, PackRGBA([0.2, 0.25, 0.3, 1.0]));
                }
                if(g_render_state.current_program.hasOwnProperty("Kr"))
                {
                    gl.uniform1f(g_render_state.current_program.Kr, PackRGBA([0.0, 0.0, 0.0, 0.0]));
                }
            }
        },
        "chrome" : {
            Use : function(){
                "use strict";
                if(g_render_state.current_program.hasOwnProperty("Kd"))
                {
                    gl.uniform1f(g_render_state.current_program.Kd, PackRGBA([0.4, 0.4, 0.4, 1.0]));
                }
                if(g_render_state.current_program.hasOwnProperty("Ka"))
                {
                    gl.uniform1f(g_render_state.current_program.Ka, PackRGBA([0.1, 0.1, 0.1, 0.0]));
                }
                if(g_render_state.current_program.hasOwnProperty("Kr"))
                {
                    gl.uniform1f(g_render_state.current_program.Kr, PackRGBA([0.4, 0.4, 0.4, 1.0]));
                }
            }
        },
        "dark_matte" : {
            Use : function(){
                "use strict";
                if(g_render_state.current_program.hasOwnProperty("Kd"))
                {
                    gl.uniform1f(g_render_state.current_program.Kd, PackRGBA([0.0, 0.0, 0.0, 1.0]));
                }
                if(g_render_state.current_program.hasOwnProperty("Ka"))
                {
                    gl.uniform1f(g_render_state.current_program.Ka, PackRGBA([0.05, 0.05, 0.05, 0.0]));
                }
                if(g_render_state.current_program.hasOwnProperty("Kr"))
                {
                    gl.uniform1f(g_render_state.current_program.Kr, PackRGBA([0.0, 0.0, 0.0, 0.0]));
                }
            }
        },
        "world" : {
            Use : function(){
                "use strict";
                if(g_render_state.current_program.hasOwnProperty("Kd"))
                {
                    gl.uniform1f(g_render_state.current_program.Kd, PackRGBA([1.0, 1.0, 1.0, 1.0]));
                }
                if(g_render_state.current_program.hasOwnProperty("Ka"))
                {
                    gl.uniform1f(g_render_state.current_program.Ka, PackRGBA([0.2, 0.25, 0.3, 1.0, 1.0]));
                }
                if(g_render_state.current_program.hasOwnProperty("Kr"))
                {
                    gl.uniform1f(g_render_state.current_program.Kr, PackRGBA([0.0, 0.0, 0.0, 0.0]));
                }
            }
        }
    };
    
        
    var PackRGBA = function(rgba){
        "use strict";
        rgba[0] = Math.max(Math.floor(rgba[0]*128.0)/128.0 - 1/128, 0.0);
        rgba[1] = Math.max(Math.floor(rgba[1]*128.0)/128.0 - 1/128, 0.0);
        rgba[2] = Math.max(Math.floor(rgba[2]*128.0)/128.0 - 1/128, 0.0);
        rgba[3] = Math.max(Math.floor(rgba[3]*128.0)/128.0 - 9/128, 0.0);
        //alert((rgba[3]/(256.0*256.0*256.0) + rgba[2]/(256.0*256.0) + rgba[1]/(256.0) + rgba[0]));
        return (rgba[3]/(128.0*128.0*128.0) + rgba[2]/(128.0*128.0) + rgba[1]/(128.0) + rgba[0]);
    };
    
    var UnPackRGBA = function(single_float){
        "use strict";
        var rgba = [single_float*1.0, single_float*128.0, single_float*128.0*128.0, single_float*128.0*128.0*128.0];

        rgba[0] = rgba[0] %1;
        rgba[1] = rgba[1] %1;
        rgba[2] = rgba[2] %1;
        rgba[3] = rgba[3] %1;

        rgba[0] -= rgba[1] / 128.0;
        rgba[1] -= rgba[2] / 128.0;
        rgba[2] -= rgba[3] / 128.0;
        return rgba;
    };
    

    /***************************************************************************/
    
    var g_mouse_x = 0.0,
        g_mouse_y = 0.0,
        
        g_mouse_dx = 0.0,
        g_mouse_dy = 0.0;
    
    var GetClick = function(e){
        "use strict";
        var x,
            y;
        if (e.pageX || e.pageY)
        {
            x = e.pageX;
            y = e.pageY;
        } else
        {
            x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
            y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
        }
        x -= g_canvas.offsetLeft;
        y -= g_canvas.offsetTop;
        
        x /= g_canvas.width;
        y /= g_canvas.height;
        
        x = x * 2 - 1;
        y = -y * 2 + 1;
        
        //console.log(x, y);
        
        ListenClick(x, y);
        
        g_mouse_x = x;
        g_mouse_y = y;
    };
        
    var GetMove = function(e){
        "use strict";
        var x,
            y;
        if (e.pageX || e.pageY)
        {
            x = e.pageX;
            y = e.pageY;
        }else
        {
            x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
            y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
        }
        x -= g_canvas.offsetLeft;
        y -= g_canvas.offsetTop;
        
        x /= g_canvas.width;
        y /= g_canvas.height;
        
        x = x * 2 - 1;
        y = -y * 2 + 1;
        
        g_mouse_dx = x - g_mouse_x;
        g_mouse_dy = y - g_mouse_y;
        
        ListenMove(g_mouse_x, g_mouse_y);
        
        g_mouse_x = x;
        g_mouse_y = y;
        

    };
            
    var GetUp = function(e){
        "use strict";
        var x,
            y;
        if (e.pageX || e.pageY)
        {
            x = e.pageX;
            y = e.pageY;
        } else
        {
            x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
            y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
        }
        x -= g_canvas.offsetLeft;
        y -= g_canvas.offsetTop;
        
        x /= g_canvas.width;
        y /= g_canvas.height;
        
        x = x * 2 - 1;
        y = -y * 2 + 1;
        
        g_mouse_x = x;
        g_mouse_y = y;
        
        ListenUp(x, y);

    };

/***************************************************************************/